using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Interop;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Converters;
using System.Windows.Media.Composition;
using System.Windows.Media.Animation;
using System.Windows.Media.Media3D;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using Wrappers;

namespace Sidebar
{
    internal class Flyout
    {
        // Methods
        private static UIElement addBGToFlyout(FrameworkElement frameworkElement, Popup flyout)
        {
            Border border3 = new Border();
            border3.BorderBrush = Brushes.Black;
            border3.BorderThickness = new Thickness(1.0);
            Border border = border3;
            Border border4 = new Border();
            border4.BorderBrush = new SolidColorBrush(Color.FromArgb(170, 200, 200, 200));
            border4.BorderThickness = new Thickness(1.0);
            Border border2 = border4;
            Grid grid = new Grid();
            ColumnDefinition definition = new ColumnDefinition();
            definition.Width = GridLength.Auto;
            ColumnDefinition definition2 = new ColumnDefinition();
            definition2.Width = new GridLength(1.0, GridUnitType.Star);
            grid.ColumnDefinitions.Add(definition);
            grid.ColumnDefinitions.Add(definition2);
            RowDefinition definition3 = new RowDefinition();
            definition3.Height = GridLength.Auto;
            RowDefinition definition4 = new RowDefinition();
            definition4.Height = new GridLength(1.0, GridUnitType.Star);
            grid.RowDefinitions.Add(definition3);
            grid.RowDefinitions.Add(definition4);
            grid.Background = new SolidColorBrush(Color.FromArgb(170, 0, 0, 0));
            Pin element = new Pin(flyout);
            element.HorizontalAlignment = HorizontalAlignment.Right;
            element.Margin = new Thickness(0.0, 3.0, 5.0, 3.0);
            grid.Children.Add(element);
            Grid.SetColumn(element, 1);
            Grid.SetRow(element, 0);
            Grid.SetRowSpan(element, 1);
            Grid.SetColumnSpan(element, 1);
            Grid grid2 = makeGlare();
            grid.Children.Add(grid2);
            Grid.SetColumn(grid2, 0);
            Grid.SetRow(grid2, 0);
            Grid.SetRowSpan(grid2, 2);
            Grid.SetColumnSpan(grid2, 1);
            grid.Children.Add(frameworkElement);
            Grid.SetColumn(frameworkElement, 0);
            Grid.SetRow(frameworkElement, 1);
            Grid.SetRowSpan(frameworkElement, 1);
            Grid.SetColumnSpan(frameworkElement, 2);
            border.Child = border2;
            border2.Child = grid;
            return border;
        }

        private static void flyout_Closed(object sender, EventArgs e)
        {
            Popup popup = (Popup)sender;
            Border child = (Border)((Border)popup.Child).Child;
            ((Grid)child.Child).Children.Clear();
        }

        private static Grid makeGlare()
        {
            Grid grid2 = new Grid();
            LinearGradientBrush brush2 = new LinearGradientBrush();
            brush2.StartPoint = new Point(0.0, 0.5);
            brush2.EndPoint = new Point(1.0, 0.5);
            brush2.GradientStops.Add(new GradientStop(Color.FromArgb(40, 0xff, 0xff, 0xff), 0.0));
            brush2.GradientStops.Add(new GradientStop(Color.FromArgb(0, 0xff, 0xff, 0xff), 1.0));
            grid2.Background = brush2;
            grid2.Width = 80.0;
            Grid grid = grid2;
            Path path2 = new Path();
            path2.Stretch = Stretch.Fill;
            path2.Width = 80.0;
            path2.Data = Geometry.Parse("M 0.05,0 Q 0.25,0.5 0.05,1 L 0.45,1 Q 0.6,0.5, 0.45,0 L 0.025,0");
            Path element = path2;
            LinearGradientBrush brush3 = new LinearGradientBrush();
            brush3.StartPoint = new Point(0.0, 0.5);
            brush3.EndPoint = new Point(1.0, 0.5);
            brush3.GradientStops.Add(new GradientStop(Color.FromArgb(110, 0xff, 0xff, 0xff), 0.0));
            brush3.GradientStops.Add(new GradientStop(Color.FromArgb(30, 0xff, 0xff, 0xff), 0.75));
            brush3.GradientStops.Add(new GradientStop(Color.FromArgb(15, 0xff, 0xff, 0xff), 1.0));
            LinearGradientBrush brush = brush3;
            element.Fill = brush;
            grid.Children.Add(element);
            return grid;
        }

        public static void showFlyout(UIElement owner, FrameworkElement element)
        {
            Popup popup2 = new Popup();
            popup2.AllowsTransparency = true;
            popup2.StaysOpen = false;
            popup2.PlacementTarget = owner;
            popup2.Placement = PlacementMode.Center;
            Popup flyout = popup2;
            flyout.Child = addBGToFlyout(element, flyout);
            flyout.Closed += new EventHandler(Flyout.flyout_Closed);
            flyout.IsOpen = true;
            if (Dwm.IsEnabled())
            {
                System.Drawing.Region region = new System.Drawing.Region();
                region.MakeInfinite();
                HwndSource source = PresentationSource.FromVisual(flyout.Child) as HwndSource;
                IntPtr handle = source.Handle;
                System.Drawing.Graphics g = System.Drawing.Graphics.FromHwnd(handle);
                Dwm.SetBlurBehindClientArea(handle, Dwm.BlurBehindWindowFlags.TransitionOnMaximized | Dwm.BlurBehindWindowFlags.BlurRegion | Dwm.BlurBehindWindowFlags.Enable, true, region.GetHrgn(g), false);
            }
        }

        // Nested Types
        internal class Pin : Canvas
        {
            // Fields
            private Popup flyout;
            private const double height = 15.0;
            private HwndSource hs;
            private bool isPinned = true;
            private const int SC_MOVE = 0xf010;
            private const double width = 15.0;
            private const int WM_SYSCOMMAND = 0x112;

            // Methods
            public Pin(Popup slave)
            {
                this.flyout = slave;
                base.Height = 15.0;
                base.Width = 15.0;
                base.Loaded += new RoutedEventHandler(this.Pin_Loaded);
                base.MouseUp += new MouseButtonEventHandler(this.Pin_MouseUp);
                base.Children.Add(this.makeArrow());
            }

            private void flyout_MouseDown(object sender, MouseButtonEventArgs e)
            {
                if ((e.ChangedButton == MouseButton.Left) && (e.OriginalSource.GetType() != typeof(Path)))
                {
                    IntPtr handle = this.hs.Handle;
                    ReleaseCapture();
                    SendMessage(handle, 0x112, 0xf012, 0);
                    e.Handled = true;
                }
            }

            public Path makeArrow()
            {
                Path path = new Path();
                path.Data = Geometry.Parse("M 15,5 L 7.5,5 L 7.5,0 L 0,7.5 L 7.5,15 L 7.5,10 L 15,10 L 15,5");
                path.Fill = Brushes.LightGray;
                return path;
            }

            public Path makeCross()
            {
                Path path = new Path();
                path.Data = Geometry.Parse("M 3.25,0 L 7.5,5.5 L 10.75,0 L 15,3.25 L 9.5,7.5 L 15,10.75 L 10.75,15 L 7.5,9.5 L 3.75,15 L 0,10.75 L 5.5,7.5 L 0,3.25 L 3.25,0");
                path.Fill = Brushes.DarkRed;
                path.Stroke = Brushes.Black;
                path.StrokeThickness = 1.0;
                return path;
            }

            private void Pin_Loaded(object sender, RoutedEventArgs e)
            {
                this.hs = (HwndSource)PresentationSource.FromVisual(this.flyout.Child);
                SendMessage(this.hs.Handle, 0x112, 0xf012, 0);
            }

            private void Pin_MouseUp(object sender, MouseButtonEventArgs e)
            {
                if (e.ChangedButton == MouseButton.Left)
                {
                    Point point;
                    if (this.isPinned)
                    {
                        this.flyout.StaysOpen = true;
                        this.isPinned = false;
                        this.flyout.MouseDown += new MouseButtonEventHandler(this.flyout_MouseDown);
                        base.Children.Clear();
                        base.Children.Add(this.makeCross());
                        point = base.PointToScreen(new Point(0.0, 0.0));
                        SetWindowPos(this.hs.Handle, -2, ((int)point.X) - ((int)this.flyout.Child.RenderSize.Width), (int)point.Y, 0, 0, 0x200);
                    }
                    else
                    {
                        point = base.PointToScreen(new Point(0.0, 0.0));
                        SetWindowPos(((HwndSource)PresentationSource.FromVisual(Application.Current.MainWindow)).Handle, -1, ((int)point.X) - ((int)this.flyout.Child.RenderSize.Width), (int)point.Y, 0, 0, 3);
                        this.flyout.IsOpen = false;
                    }
                    e.Handled = true;
                }
            }

            [DllImport("user32.dll")]
            public static extern bool ReleaseCapture();
            [DllImport("user32.dll")]
            public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
            [DllImport("user32")]
            private static extern int SetWindowPos(IntPtr hwnd, int hwndInsertAfter, int x, int y, int cx, int cy, int wFlags);
        }
    }


}
